/*
 * Copyright 2007 National Bioinformatics Network
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package dgbgui.gui.widgets.visual;

import java.awt.Color;
import java.awt.geom.Point2D;

import dgbgui.gui.widgets.EmptyWidget;
import dgbgui.gui.widgets.Highlightable;
import dgbgui.gui.widgets.Widget;
import dgbgui.gui.widgets.WidgetFactory;
import dgbgui.gui.widgets.layouts.VerticalLayout;
import dgbgui.gui.widgets.visual.definition.ResultsDefinitionWidget;
import dgbgui.modeldocument.Query;
import dgbgui.modeldocument.ResultStore;
import edu.umd.cs.piccolo.PNode;

public class QueryWidget extends RectangleBorder implements Highlightable {
    

    /**
     * Default serial verion ID
     */
    private static final long serialVersionUID = 1L;

    public QueryWidget(PNode parent, Query query) {
        super(parent,5,0);
        m_query = query;
        
        // The border is just a placeholder for using ports, so make transparent
        setStrokeColor(new Color(0,0,0,0));
        //setFillColor(new Color(0,0,0,0));
        VerticalLayout layout = new VerticalLayout(this,0,0);
        
        // Initial, default state. Current position, both definition and result
        // expanded and not selected
        m_state = new QueryWidgetState(query.getState().getPosition(),true,true);
       
        // Use placeholders which will be replaced so we don't duplicate
        // code for updates
        m_titleBar = new EmptyWidget(layout);
        m_definition = new EmptyWidget(layout);
        m_results = new EmptyWidget(layout);
        updateDefinition();
        updateResult();
        
        m_savedDefinitionWidget = m_definition;
        m_savedResultsWidget = m_results;
        // Update for the enable/disable of the minimize and miximize widgets
        updateTitleBar();
        m_originalFillColor = m_titleBar.getOwnFillColour();
        unhighlight();
        
    }
    
    public Query getQuery() {
        return m_query;
    }
    
    public Widget getResultsWidget() {
        return m_results;
    }
    
    
    public void highlight() {
        // For highlighting, store the widget's own fill
        // colour, instead of using the colour that's inherited
        // since that same colour will be restored on unhighlighting
        // (the colour could also be null)
        m_originalFillColor = m_titleBar.getOwnFillColour();
        m_titleBar.setFillColor(Color.yellow);
    }
    
    public void unhighlight() {
        m_titleBar.setFillColor(m_originalFillColor);
    }
    
    
    /**
     * Update the title of the query
     */
    public void updateTitleBar() {
        Widget newTitle = new TitleBarWidget(
                m_query,
                m_titleBar.getParent(),
                m_query.getDefinition().getTypeName() + " : " + m_query.getLabel(),
                m_state.isDefinitionExpanded(),
                m_state.isResultExpanded(),
                (!(m_savedDefinitionWidget instanceof ResultsDefinitionWidget)),
                ResultStore.getInstance().hasResult(m_query) || ResultStore.getInstance().hasBeenSubmitted(m_query));
        m_titleBar.replaceWith(newTitle);
        m_titleBar = newTitle;
    }
    
    /**
     * Update the definition representation from the query
     */
    public void updateDefinition() {
        Widget newDef;
        if ( m_state.isDefinitionExpanded() ) {
            newDef = WidgetFactory.createWidget(
                    m_definition.getParent(),
                    m_query.getDefinition());
        } else {
            newDef = new EmptyWidget(m_definition.getParent());
        }
        m_definition.replaceWith(newDef);
        m_definition = newDef;
    }
    

    
    /**
     * Update the result representation from the query
     */
    public void updateResult() {
        Widget newResult = null;
        if ( m_state.isResultExpanded() ) {
            if ( ResultStore.getInstance().hasResult(m_query) ) {
                // Create the results widget
                newResult = WidgetFactory.createWidget(m_results.getParent(),ResultStore.getInstance().getResult(m_query));
            } else if ( ResultStore.getInstance().hasBeenSubmitted(m_query) ) {
                //  If the query has been submitted, but no result received yet,
                // add an "in progress" result widget
                newResult = new RotatingProgressWidget(m_results.getParent());
            }
        }
        
        if ( newResult == null ) {
            newResult = new EmptyWidget(m_definition.getParent());
        }

        // Replace in the hierarchy and store locally
        m_results.replaceWith(newResult);
        m_results = newResult;

        // Min/Max changes according the result widget
        updateTitleBar();
    }
    
    /**
     * Updated the expanded status of the definition
     * @param expanded true if expanded
     */
    public void updateDefinitionExpanded(boolean expanded) {
        m_state.setDefinitionExpanded(expanded);
        if ( expanded ) {
            // There should be a saved widget, replace the
            // current definition widget in the scene graph
            m_definition.replaceWith(m_savedDefinitionWidget);
            m_definition = m_savedDefinitionWidget;
        }
        else {
            // Save the current definition and set the current definition
            // as empty
            m_savedDefinitionWidget = m_definition;
            Widget newDef = new EmptyWidget(m_definition.getParent());
            // Replace in the scene graph
            m_definition.replaceWith(newDef);
            m_definition = newDef;
        }
        updateTitleBar();
    }
    
    /**
     * Updated the expanded status of the result
     * @param expanded true if expanded
     */
    public void updateResultExpanded(boolean expanded) {
        m_state.setResultExpanded(expanded);
        if ( expanded ) {
            // There should be a saved widget, replace the
            // current results widget in the scene graph
            m_results.replaceWith(m_savedResultsWidget);
            m_results = m_savedResultsWidget;
        }
        else {
            // Save the current result and set the current result
            // as empty
            m_savedResultsWidget = m_results;
            Widget newDef = new EmptyWidget(m_results.getParent());
            // Replace in the scene graph
            m_results.replaceWith(newDef);
            m_results = newDef;
        }
        updateTitleBar();
    }
    
    public void restoreOriginalStyle() {
        unhighlight();
    }
    


    public void translate(double dx, double dy) {
        setOffset(new Point2D.Double(
                m_state.getPosition().getX() + dx,
                m_state.getPosition().getY() + dy));
        
    }
    
    public void translate(int dx, int dy) {
        setOffset(new Point2D.Double(
                m_state.getPosition().getX() + dx,
                m_state.getPosition().getY() + dy));
    }
    

    public void setOffset(Point2D position) {
        m_state.setPosition(new Point2D.Double(
                position.getX(),
                position.getY()));
        m_query.getState().setPosition(position);
        super.setOffset(position);
        
    }

    
    /**
     * @return A deep copy of the widget state
     */
    public QueryWidgetState getWidgetStateCopy() {
        return (QueryWidgetState)m_state.clone();
    }
    
    public void setState(QueryWidgetState state) {
        setOffset(state.getPosition());
        m_query.getState().setPosition(state.getPosition());
    }

    public boolean isDefinitionMinMaxWidget(Widget widget) {
        return ( widget == ((TitleBarWidget)m_titleBar).getDefinitionMinMaxWidget() ); 
    }
    
    // Visual widgets
    Widget m_titleBar;
    Widget m_definition;
    Widget m_results;
    
    // Saved definition and result
    Widget m_savedDefinitionWidget;
    Widget m_savedResultsWidget;
    
    // The fill color of the title bar before highlighting
    Color m_originalFillColor;
    
    // The current widget state
    QueryWidgetState m_state;
    
    // The query of this widget
    // DONT make this publicly accesible as the Widgetstore must be used
    // to get queries from the widget
    Query m_query;
    
    MinimizeWidget m_definitionMinimizeWidget,m_resultMinimizeWidget;
    
}
